/*
 * Copyright (C) 2007 The Android Open Source Project
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */

package com.badlogic.gdx.backends.android.surfaceview;

import java.io.IOException;
import java.io.Writer;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.CharBuffer;
import java.nio.DoubleBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.LongBuffer;
import java.nio.ShortBuffer;
import java.util.Arrays;

import javax.microedition.khronos.opengles.GL;

/** A wrapper that logs all GL calls (and results) in human-readable form. */
class GLLogWrapper extends GLWrapperBase {
	private static final int FORMAT_INT = 0;
	private static final int FORMAT_FLOAT = 1;
	private static final int FORMAT_FIXED = 2;

	public GLLogWrapper (GL gl, Writer log, boolean logArgumentNames) {
		super(gl);
		mLog = log;
		mLogArgumentNames = logArgumentNames;
	}

	private void checkError () {
		int glError;
		if ((glError = mgl.glGetError()) != 0) {
			String errorMessage = "glError: " + Integer.toString(glError);
			logLine(errorMessage);
		}
	}

	private void logLine (String message) {
		log(message + '\n');
	}

	private void log (String message) {
		try {
			mLog.write(message);
		} catch (IOException e) {
			// Ignore exception, keep on trying
		}
	}

	private void begin (String name) {
		log(name + '(');
		mArgCount = 0;
	}

	private void arg (String name, String value) {
		if (mArgCount++ > 0) {
			log(", ");
		}
		if (mLogArgumentNames) {
			log(name + "=");
		}
		log(value);
	}

	private void end () {
		log(");\n");
		flush();
	}

	private void flush () {
		try {
			mLog.flush();
		} catch (IOException e) {
			mLog = null;
		}
	}

	private void arg (String name, boolean value) {
		arg(name, Boolean.toString(value));
	}

	private void arg (String name, int value) {
		arg(name, Integer.toString(value));
	}

	private void arg (String name, float value) {
		arg(name, Float.toString(value));
	}

	private void returns (String result) {
		log(") returns " + result + ";\n");
		flush();
	}

	private void returns (int result) {
		returns(Integer.toString(result));
	}

	private void arg (String name, int n, int[] arr, int offset) {
		arg(name, toString(n, FORMAT_INT, arr, offset));
	}

	private void arg (String name, int n, short[] arr, int offset) {
		arg(name, toString(n, arr, offset));
	}

	private void arg (String name, int n, float[] arr, int offset) {
		arg(name, toString(n, arr, offset));
	}

	private void formattedAppend (StringBuilder buf, int value, int format) {
		switch (format) {
		case FORMAT_INT:
			buf.append(value);
			break;
		case FORMAT_FLOAT:
			buf.append(Float.intBitsToFloat(value));
			break;
		case FORMAT_FIXED:
			buf.append(value / 65536.0f);
			break;
		}
	}

	private String toString (int n, int format, int[] arr, int offset) {
		StringBuilder buf = new StringBuilder();
		buf.append("{\n");
		int arrLen = arr.length;
		for (int i = 0; i < n; i++) {
			int index = offset + i;
			buf.append(" [" + index + "] = ");
			if (index < 0 || index >= arrLen) {
				buf.append("out of bounds");
			} else {
				formattedAppend(buf, arr[index], format);
			}
			buf.append('\n');
		}
		buf.append("}");
		return buf.toString();
	}

	private String toString (int n, short[] arr, int offset) {
		StringBuilder buf = new StringBuilder();
		buf.append("{\n");
		int arrLen = arr.length;
		for (int i = 0; i < n; i++) {
			int index = offset + i;
			buf.append(" [" + index + "] = ");
			if (index < 0 || index >= arrLen) {
				buf.append("out of bounds");
			} else {
				buf.append(arr[index]);
			}
			buf.append('\n');
		}
		buf.append("}");
		return buf.toString();
	}

	private String toString (int n, float[] arr, int offset) {
		StringBuilder buf = new StringBuilder();
		buf.append("{\n");
		int arrLen = arr.length;
		for (int i = 0; i < n; i++) {
			int index = offset + i;
			buf.append("[" + index + "] = ");
			if (index < 0 || index >= arrLen) {
				buf.append("out of bounds");
			} else {
				buf.append(arr[index]);
			}
			buf.append('\n');
		}
		buf.append("}");
		return buf.toString();
	}

	private String toString (int n, FloatBuffer buf) {
		StringBuilder builder = new StringBuilder();
		builder.append("{\n");
		for (int i = 0; i < n; i++) {
			builder.append(" [" + i + "] = " + buf.get(i) + '\n');
		}
		builder.append("}");
		return builder.toString();
	}

	private String toString (int n, int format, IntBuffer buf) {
		StringBuilder builder = new StringBuilder();
		builder.append("{\n");
		for (int i = 0; i < n; i++) {
			builder.append(" [" + i + "] = ");
			formattedAppend(builder, buf.get(i), format);
			builder.append('\n');
		}
		builder.append("}");
		return builder.toString();
	}

	private String toString (int n, ShortBuffer buf) {
		StringBuilder builder = new StringBuilder();
		builder.append("{\n");
		for (int i = 0; i < n; i++) {
			builder.append(" [" + i + "] = " + buf.get(i) + '\n');
		}
		builder.append("}");
		return builder.toString();
	}

	private void arg (String name, int n, FloatBuffer buf) {
		arg(name, toString(n, buf));
	}

	private void arg (String name, int n, IntBuffer buf) {
		arg(name, toString(n, FORMAT_INT, buf));
	}

	private void arg (String name, int n, ShortBuffer buf) {
		arg(name, toString(n, buf));
	}

	private void argPointer (int size, int type, int stride, Buffer pointer) {
		arg("size", size);
		arg("type", getPointerTypeName(type));
		arg("stride", stride);
		arg("pointer", pointer.toString());
	}

	private static String getHex (int value) {
		return "0x" + Integer.toHexString(value);
	}

	public static String getErrorString (int error) {
		switch (error) {
		case GL_NO_ERROR:
			return "GL_NO_ERROR";
		case GL_INVALID_ENUM:
			return "GL_INVALID_ENUM";
		case GL_INVALID_VALUE:
			return "GL_INVALID_VALUE";
		case GL_INVALID_OPERATION:
			return "GL_INVALID_OPERATION";
		case GL_STACK_OVERFLOW:
			return "GL_STACK_OVERFLOW";
		case GL_STACK_UNDERFLOW:
			return "GL_STACK_UNDERFLOW";
		case GL_OUT_OF_MEMORY:
			return "GL_OUT_OF_MEMORY";
		default:
			return getHex(error);
		}
	}

	private String getClearBufferMask (int mask) {
		StringBuilder b = new StringBuilder();
		if ((mask & GL_DEPTH_BUFFER_BIT) != 0) {
			b.append("GL_DEPTH_BUFFER_BIT");
			mask &= ~GL_DEPTH_BUFFER_BIT;
		}
		if ((mask & GL_STENCIL_BUFFER_BIT) != 0) {
			if (b.length() > 0) {
				b.append(" | ");
			}
			b.append("GL_STENCIL_BUFFER_BIT");
			mask &= ~GL_STENCIL_BUFFER_BIT;
		}
		if ((mask & GL_COLOR_BUFFER_BIT) != 0) {
			if (b.length() > 0) {
				b.append(" | ");
			}
			b.append("GL_COLOR_BUFFER_BIT");
			mask &= ~GL_COLOR_BUFFER_BIT;
		}
		if (mask != 0) {
			if (b.length() > 0) {
				b.append(" | ");
			}
			b.append(getHex(mask));
		}
		return b.toString();
	}

	private String getFactor (int factor) {
		switch (factor) {
		case GL_ZERO:
			return "GL_ZERO";
		case GL_ONE:
			return "GL_ONE";
		case GL_SRC_COLOR:
			return "GL_SRC_COLOR";
		case GL_ONE_MINUS_SRC_COLOR:
			return "GL_ONE_MINUS_SRC_COLOR";
		case GL_DST_COLOR:
			return "GL_DST_COLOR";
		case GL_ONE_MINUS_DST_COLOR:
			return "GL_ONE_MINUS_DST_COLOR";
		case GL_SRC_ALPHA:
			return "GL_SRC_ALPHA";
		case GL_ONE_MINUS_SRC_ALPHA:
			return "GL_ONE_MINUS_SRC_ALPHA";
		case GL_DST_ALPHA:
			return "GL_DST_ALPHA";
		case GL_ONE_MINUS_DST_ALPHA:
			return "GL_ONE_MINUS_DST_ALPHA";
		case GL_SRC_ALPHA_SATURATE:
			return "GL_SRC_ALPHA_SATURATE";

		default:
			return getHex(factor);
		}
	}

	private String getShadeModel (int model) {
		switch (model) {
		case GL_FLAT:
			return "GL_FLAT";
		case GL_SMOOTH:
			return "GL_SMOOTH";
		default:
			return getHex(model);
		}
	}

	private String getTextureTarget (int target) {
		switch (target) {
		case GL_TEXTURE_2D:
			return "GL_TEXTURE_2D";
		default:
			return getHex(target);
		}
	}

	private String getTextureEnvTarget (int target) {
		switch (target) {
		case GL_TEXTURE_ENV:
			return "GL_TEXTURE_ENV";
		default:
			return getHex(target);
		}
	}

	private String getTextureEnvPName (int pname) {
		switch (pname) {
		case GL_TEXTURE_ENV_MODE:
			return "GL_TEXTURE_ENV_MODE";
		case GL_TEXTURE_ENV_COLOR:
			return "GL_TEXTURE_ENV_COLOR";
		default:
			return getHex(pname);
		}
	}

	private int getTextureEnvParamCount (int pname) {
		switch (pname) {
		case GL_TEXTURE_ENV_MODE:
			return 1;
		case GL_TEXTURE_ENV_COLOR:
			return 4;
		default:
			return 0;
		}
	}

	private String getTextureEnvParamName (float param) {
		int iparam = (int)param;
		if (param == (float)iparam) {
			switch (iparam) {
			case GL_REPLACE:
				return "GL_REPLACE";
			case GL_MODULATE:
				return "GL_MODULATE";
			case GL_DECAL:
				return "GL_DECAL";
			case GL_BLEND:
				return "GL_BLEND";
			case GL_ADD:
				return "GL_ADD";
			case GL_COMBINE:
				return "GL_COMBINE";
			default:
				return getHex(iparam);
			}
		}
		return Float.toString(param);
	}

	private String getMatrixMode (int matrixMode) {
		switch (matrixMode) {
		case GL_MODELVIEW:
			return "GL_MODELVIEW";
		case GL_PROJECTION:
			return "GL_PROJECTION";
		case GL_TEXTURE:
			return "GL_TEXTURE";
		default:
			return getHex(matrixMode);
		}
	}

	private String getClientState (int clientState) {
		switch (clientState) {
		case GL_COLOR_ARRAY:
			return "GL_COLOR_ARRAY";
		case GL_VERTEX_ARRAY:
			return "GL_VERTEX_ARRAY";
		case GL_NORMAL_ARRAY:
			return "GL_NORMAL_ARRAY";
		case GL_TEXTURE_COORD_ARRAY:
			return "GL_TEXTURE_COORD_ARRAY";
		default:
			return getHex(clientState);
		}
	}

	private String getCap (int cap) {
		switch (cap) {
		case GL_FOG:
			return "GL_FOG";
		case GL_LIGHTING:
			return "GL_LIGHTING";
		case GL_TEXTURE_2D:
			return "GL_TEXTURE_2D";
		case GL_CULL_FACE:
			return "GL_CULL_FACE";
		case GL_ALPHA_TEST:
			return "GL_ALPHA_TEST";
		case GL_BLEND:
			return "GL_BLEND";
		case GL_COLOR_LOGIC_OP:
			return "GL_COLOR_LOGIC_OP";
		case GL_DITHER:
			return "GL_DITHER";
		case GL_STENCIL_TEST:
			return "GL_STENCIL_TEST";
		case GL_DEPTH_TEST:
			return "GL_DEPTH_TEST";
		case GL_LIGHT0:
			return "GL_LIGHT0";
		case GL_LIGHT1:
			return "GL_LIGHT1";
		case GL_LIGHT2:
			return "GL_LIGHT2";
		case GL_LIGHT3:
			return "GL_LIGHT3";
		case GL_LIGHT4:
			return "GL_LIGHT4";
		case GL_LIGHT5:
			return "GL_LIGHT5";
		case GL_LIGHT6:
			return "GL_LIGHT6";
		case GL_LIGHT7:
			return "GL_LIGHT7";
		case GL_POINT_SMOOTH:
			return "GL_POINT_SMOOTH";
		case GL_LINE_SMOOTH:
			return "GL_LINE_SMOOTH";
		case GL_COLOR_MATERIAL:
			return "GL_COLOR_MATERIAL";
		case GL_NORMALIZE:
			return "GL_NORMALIZE";
		case GL_RESCALE_NORMAL:
			return "GL_RESCALE_NORMAL";
		case GL_VERTEX_ARRAY:
			return "GL_VERTEX_ARRAY";
		case GL_NORMAL_ARRAY:
			return "GL_NORMAL_ARRAY";
		case GL_COLOR_ARRAY:
			return "GL_COLOR_ARRAY";
		case GL_TEXTURE_COORD_ARRAY:
			return "GL_TEXTURE_COORD_ARRAY";
		case GL_MULTISAMPLE:
			return "GL_MULTISAMPLE";
		case GL_SAMPLE_ALPHA_TO_COVERAGE:
			return "GL_SAMPLE_ALPHA_TO_COVERAGE";
		case GL_SAMPLE_ALPHA_TO_ONE:
			return "GL_SAMPLE_ALPHA_TO_ONE";
		case GL_SAMPLE_COVERAGE:
			return "GL_SAMPLE_COVERAGE";
		case GL_SCISSOR_TEST:
			return "GL_SCISSOR_TEST";
		default:
			return getHex(cap);
		}
	}

	private String getTexturePName (int pname) {
		switch (pname) {
		case GL_TEXTURE_MAG_FILTER:
			return "GL_TEXTURE_MAG_FILTER";
		case GL_TEXTURE_MIN_FILTER:
			return "GL_TEXTURE_MIN_FILTER";
		case GL_TEXTURE_WRAP_S:
			return "GL_TEXTURE_WRAP_S";
		case GL_TEXTURE_WRAP_T:
			return "GL_TEXTURE_WRAP_T";
		case GL_GENERATE_MIPMAP:
			return "GL_GENERATE_MIPMAP";
		case GL_TEXTURE_CROP_RECT_OES:
			return "GL_TEXTURE_CROP_RECT_OES";
		default:
			return getHex(pname);
		}
	}

	private String getTextureParamName (float param) {
		int iparam = (int)param;
		if (param == (float)iparam) {
			switch (iparam) {
			case GL_CLAMP_TO_EDGE:
				return "GL_CLAMP_TO_EDGE";
			case GL_REPEAT:
				return "GL_REPEAT";
			case GL_NEAREST:
				return "GL_NEAREST";
			case GL_LINEAR:
				return "GL_LINEAR";
			case GL_NEAREST_MIPMAP_NEAREST:
				return "GL_NEAREST_MIPMAP_NEAREST";
			case GL_LINEAR_MIPMAP_NEAREST:
				return "GL_LINEAR_MIPMAP_NEAREST";
			case GL_NEAREST_MIPMAP_LINEAR:
				return "GL_NEAREST_MIPMAP_LINEAR";
			case GL_LINEAR_MIPMAP_LINEAR:
				return "GL_LINEAR_MIPMAP_LINEAR";
			default:
				return getHex(iparam);
			}
		}
		return Float.toString(param);
	}

	private String getFogPName (int pname) {
		switch (pname) {
		case GL_FOG_DENSITY:
			return "GL_FOG_DENSITY";
		case GL_FOG_START:
			return "GL_FOG_START";
		case GL_FOG_END:
			return "GL_FOG_END";
		case GL_FOG_MODE:
			return "GL_FOG_MODE";
		case GL_FOG_COLOR:
			return "GL_FOG_COLOR";
		default:
			return getHex(pname);
		}
	}

	private int getFogParamCount (int pname) {
		switch (pname) {
		case GL_FOG_DENSITY:
			return 1;
		case GL_FOG_START:
			return 1;
		case GL_FOG_END:
			return 1;
		case GL_FOG_MODE:
			return 1;
		case GL_FOG_COLOR:
			return 4;
		default:
			return 0;
		}
	}

	private String getBeginMode (int mode) {
		switch (mode) {
		case GL_POINTS:
			return "GL_POINTS";
		case GL_LINES:
			return "GL_LINES";
		case GL_LINE_LOOP:
			return "GL_LINE_LOOP";
		case GL_LINE_STRIP:
			return "GL_LINE_STRIP";
		case GL_TRIANGLES:
			return "GL_TRIANGLES";
		case GL_TRIANGLE_STRIP:
			return "GL_TRIANGLE_STRIP";
		case GL_TRIANGLE_FAN:
			return "GL_TRIANGLE_FAN";
		default:
			return getHex(mode);
		}
	}

	private String getIndexType (int type) {
		switch (type) {
		case GL_UNSIGNED_SHORT:
			return "GL_UNSIGNED_SHORT";
		case GL_UNSIGNED_BYTE:
			return "GL_UNSIGNED_BYTE";
		default:
			return getHex(type);
		}
	}

	private String getIntegerStateName (int pname) {
		switch (pname) {
		case GL_ALPHA_BITS:
			return "GL_ALPHA_BITS";
		case GL_ALIASED_LINE_WIDTH_RANGE:
			return "GL_ALIASED_LINE_WIDTH_RANGE";
		case GL_ALIASED_POINT_SIZE_RANGE:
			return "GL_ALIASED_POINT_SIZE_RANGE";
		case GL_BLUE_BITS:
			return "GL_BLUE_BITS";
		case GL_COMPRESSED_TEXTURE_FORMATS:
			return "GL_COMPRESSED_TEXTURE_FORMATS";
		case GL_DEPTH_BITS:
			return "GL_DEPTH_BITS";
		case GL_GREEN_BITS:
			return "GL_GREEN_BITS";
		case GL_MAX_ELEMENTS_INDICES:
			return "GL_MAX_ELEMENTS_INDICES";
		case GL_MAX_ELEMENTS_VERTICES:
			return "GL_MAX_ELEMENTS_VERTICES";
		case GL_MAX_LIGHTS:
			return "GL_MAX_LIGHTS";
		case GL_MAX_TEXTURE_SIZE:
			return "GL_MAX_TEXTURE_SIZE";
		case GL_MAX_VIEWPORT_DIMS:
			return "GL_MAX_VIEWPORT_DIMS";
		case GL_MAX_MODELVIEW_STACK_DEPTH:
			return "GL_MAX_MODELVIEW_STACK_DEPTH";
		case GL_MAX_PROJECTION_STACK_DEPTH:
			return "GL_MAX_PROJECTION_STACK_DEPTH";
		case GL_MAX_TEXTURE_STACK_DEPTH:
			return "GL_MAX_TEXTURE_STACK_DEPTH";
		case GL_MAX_TEXTURE_UNITS:
			return "GL_MAX_TEXTURE_UNITS";
		case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
			return "GL_NUM_COMPRESSED_TEXTURE_FORMATS";
		case GL_RED_BITS:
			return "GL_RED_BITS";
		case GL_SMOOTH_LINE_WIDTH_RANGE:
			return "GL_SMOOTH_LINE_WIDTH_RANGE";
		case GL_SMOOTH_POINT_SIZE_RANGE:
			return "GL_SMOOTH_POINT_SIZE_RANGE";
		case GL_STENCIL_BITS:
			return "GL_STENCIL_BITS";
		case GL_SUBPIXEL_BITS:
			return "GL_SUBPIXEL_BITS";

		case GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES:
			return "GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES";
		case GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES:
			return "GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES";
		case GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES:
			return "GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES";

		default:
			return getHex(pname);
		}
	}

	private int getIntegerStateSize (int pname) {
		switch (pname) {
		case GL_ALPHA_BITS:
			return 1;
		case GL_ALIASED_LINE_WIDTH_RANGE:
			return 2;
		case GL_ALIASED_POINT_SIZE_RANGE:
			return 2;
		case GL_BLUE_BITS:
			return 1;
		case GL_COMPRESSED_TEXTURE_FORMATS:
		// Have to ask the implementation for the size
		{
			int[] buffer = new int[1];
			mgl.glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, buffer, 0);
			return buffer[0];
		}
		case GL_DEPTH_BITS:
			return 1;
		case GL_GREEN_BITS:
			return 1;
		case GL_MAX_ELEMENTS_INDICES:
			return 1;
		case GL_MAX_ELEMENTS_VERTICES:
			return 1;
		case GL_MAX_LIGHTS:
			return 1;
		case GL_MAX_TEXTURE_SIZE:
			return 1;
		case GL_MAX_VIEWPORT_DIMS:
			return 2;
		case GL_MAX_MODELVIEW_STACK_DEPTH:
			return 1;
		case GL_MAX_PROJECTION_STACK_DEPTH:
			return 1;
		case GL_MAX_TEXTURE_STACK_DEPTH:
			return 1;
		case GL_MAX_TEXTURE_UNITS:
			return 1;
		case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
			return 1;
		case GL_RED_BITS:
			return 1;
		case GL_SMOOTH_LINE_WIDTH_RANGE:
			return 2;
		case GL_SMOOTH_POINT_SIZE_RANGE:
			return 2;
		case GL_STENCIL_BITS:
			return 1;
		case GL_SUBPIXEL_BITS:
			return 1;

		case GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES:
		case GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES:
		case GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES:
			return 16;

		default:
			return 0;
		}
	}

	private int getIntegerStateFormat (int pname) {
		switch (pname) {
		case GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES:
		case GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES:
		case GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES:
			return FORMAT_FLOAT;

		default:
			return FORMAT_INT;
		}
	}

	private String getHintTarget (int target) {
		switch (target) {
		case GL_FOG_HINT:
			return "GL_FOG_HINT";
		case GL_LINE_SMOOTH_HINT:
			return "GL_LINE_SMOOTH_HINT";
		case GL_PERSPECTIVE_CORRECTION_HINT:
			return "GL_PERSPECTIVE_CORRECTION_HINT";
		case GL_POINT_SMOOTH_HINT:
			return "GL_POINT_SMOOTH_HINT";
		case GL_POLYGON_SMOOTH_HINT:
			return "GL_POLYGON_SMOOTH_HINT";
		case GL_GENERATE_MIPMAP_HINT:
			return "GL_GENERATE_MIPMAP_HINT";
		default:
			return getHex(target);
		}
	}

	private String getHintMode (int mode) {
		switch (mode) {
		case GL_FASTEST:
			return "GL_FASTEST";
		case GL_NICEST:
			return "GL_NICEST";
		case GL_DONT_CARE:
			return "GL_DONT_CARE";
		default:
			return getHex(mode);
		}
	}

	private String getFaceName (int face) {
		switch (face) {
		case GL_FRONT_AND_BACK:
			return "GL_FRONT_AND_BACK";
		default:
			return getHex(face);
		}
	}

	private String getMaterialPName (int pname) {
		switch (pname) {
		case GL_AMBIENT:
			return "GL_AMBIENT";
		case GL_DIFFUSE:
			return "GL_DIFFUSE";
		case GL_SPECULAR:
			return "GL_SPECULAR";
		case GL_EMISSION:
			return "GL_EMISSION";
		case GL_SHININESS:
			return "GL_SHININESS";
		case GL_AMBIENT_AND_DIFFUSE:
			return "GL_AMBIENT_AND_DIFFUSE";
		default:
			return getHex(pname);
		}
	}

	private int getMaterialParamCount (int pname) {
		switch (pname) {
		case GL_AMBIENT:
			return 4;
		case GL_DIFFUSE:
			return 4;
		case GL_SPECULAR:
			return 4;
		case GL_EMISSION:
			return 4;
		case GL_SHININESS:
			return 1;
		case GL_AMBIENT_AND_DIFFUSE:
			return 4;
		default:
			return 0;
		}
	}

	private String getLightName (int light) {
		if (light >= GL_LIGHT0 && light <= GL_LIGHT7) {
			return "GL_LIGHT" + Integer.toString(light);
		}
		return getHex(light);
	}

	private String getLightPName (int pname) {
		switch (pname) {
		case GL_AMBIENT:
			return "GL_AMBIENT";
		case GL_DIFFUSE:
			return "GL_DIFFUSE";
		case GL_SPECULAR:
			return "GL_SPECULAR";
		case GL_POSITION:
			return "GL_POSITION";
		case GL_SPOT_DIRECTION:
			return "GL_SPOT_DIRECTION";
		case GL_SPOT_EXPONENT:
			return "GL_SPOT_EXPONENT";
		case GL_SPOT_CUTOFF:
			return "GL_SPOT_CUTOFF";
		case GL_CONSTANT_ATTENUATION:
			return "GL_CONSTANT_ATTENUATION";
		case GL_LINEAR_ATTENUATION:
			return "GL_LINEAR_ATTENUATION";
		case GL_QUADRATIC_ATTENUATION:
			return "GL_QUADRATIC_ATTENUATION";
		default:
			return getHex(pname);
		}
	}

	private int getLightParamCount (int pname) {
		switch (pname) {
		case GL_AMBIENT:
			return 4;
		case GL_DIFFUSE:
			return 4;
		case GL_SPECULAR:
			return 4;
		case GL_POSITION:
			return 4;
		case GL_SPOT_DIRECTION:
			return 3;
		case GL_SPOT_EXPONENT:
			return 1;
		case GL_SPOT_CUTOFF:
			return 1;
		case GL_CONSTANT_ATTENUATION:
			return 1;
		case GL_LINEAR_ATTENUATION:
			return 1;
		case GL_QUADRATIC_ATTENUATION:
			return 1;
		default:
			return 0;
		}
	}

	private String getLightModelPName (int pname) {
		switch (pname) {
		case GL_LIGHT_MODEL_AMBIENT:
			return "GL_LIGHT_MODEL_AMBIENT";
		case GL_LIGHT_MODEL_TWO_SIDE:
			return "GL_LIGHT_MODEL_TWO_SIDE";
		default:
			return getHex(pname);
		}
	}

	private int getLightModelParamCount (int pname) {
		switch (pname) {
		case GL_LIGHT_MODEL_AMBIENT:
			return 4;
		case GL_LIGHT_MODEL_TWO_SIDE:
			return 1;
		default:
			return 0;
		}
	}

	private String getPointerTypeName (int type) {
		switch (type) {
		case GL_BYTE:
			return "GL_BYTE";
		case GL_UNSIGNED_BYTE:
			return "GL_UNSIGNED_BYTE";
		case GL_SHORT:
			return "GL_SHORT";
		case GL_FIXED:
			return "GL_FIXED";
		case GL_FLOAT:
			return "GL_FLOAT";
		default:
			return getHex(type);
		}
	}

	ByteBuffer toByteBuffer (int byteCount, Buffer input) {
		ByteBuffer result = null;
		boolean convertWholeBuffer = (byteCount < 0);
		if (input instanceof ByteBuffer) {
			ByteBuffer input2 = (ByteBuffer)input;
			if (convertWholeBuffer) {
				byteCount = input2.limit();
			}
			result = ByteBuffer.allocate(byteCount).order(input2.order());
			int position = input2.position();
			for (int i = 0; i < byteCount; i++) {
				result.put(input2.get());
			}
			input2.position(position);
		} else if (input instanceof CharBuffer) {
			CharBuffer input2 = (CharBuffer)input;
			if (convertWholeBuffer) {
				byteCount = input2.limit() * 2;
			}
			result = ByteBuffer.allocate(byteCount).order(input2.order());
			CharBuffer result2 = result.asCharBuffer();
			int position = input2.position();
			for (int i = 0; i < byteCount / 2; i++) {
				result2.put(input2.get());
			}
			input2.position(position);
		} else if (input instanceof ShortBuffer) {
			ShortBuffer input2 = (ShortBuffer)input;
			if (convertWholeBuffer) {
				byteCount = input2.limit() * 2;
			}
			result = ByteBuffer.allocate(byteCount).order(input2.order());
			ShortBuffer result2 = result.asShortBuffer();
			int position = input2.position();
			for (int i = 0; i < byteCount / 2; i++) {
				result2.put(input2.get());
			}
			input2.position(position);
		} else if (input instanceof IntBuffer) {
			IntBuffer input2 = (IntBuffer)input;
			if (convertWholeBuffer) {
				byteCount = input2.limit() * 4;
			}
			result = ByteBuffer.allocate(byteCount).order(input2.order());
			IntBuffer result2 = result.asIntBuffer();
			int position = input2.position();
			for (int i = 0; i < byteCount / 4; i++) {
				result2.put(input2.get());
			}
			input2.position(position);
		} else if (input instanceof FloatBuffer) {
			FloatBuffer input2 = (FloatBuffer)input;
			if (convertWholeBuffer) {
				byteCount = input2.limit() * 4;
			}
			result = ByteBuffer.allocate(byteCount).order(input2.order());
			FloatBuffer result2 = result.asFloatBuffer();
			int position = input2.position();
			for (int i = 0; i < byteCount / 4; i++) {
				result2.put(input2.get());
			}
			input2.position(position);
		} else if (input instanceof DoubleBuffer) {
			DoubleBuffer input2 = (DoubleBuffer)input;
			if (convertWholeBuffer) {
				byteCount = input2.limit() * 8;
			}
			result = ByteBuffer.allocate(byteCount).order(input2.order());
			DoubleBuffer result2 = result.asDoubleBuffer();
			int position = input2.position();
			for (int i = 0; i < byteCount / 8; i++) {
				result2.put(input2.get());
			}
			input2.position(position);
		} else if (input instanceof LongBuffer) {
			LongBuffer input2 = (LongBuffer)input;
			if (convertWholeBuffer) {
				byteCount = input2.limit() * 8;
			}
			result = ByteBuffer.allocate(byteCount).order(input2.order());
			LongBuffer result2 = result.asLongBuffer();
			int position = input2.position();
			for (int i = 0; i < byteCount / 8; i++) {
				result2.put(input2.get());
			}
			input2.position(position);
		} else {
			throw new RuntimeException("Unimplemented Buffer subclass.");
		}
		result.rewind();
		// The OpenGL API will interpret the result in hardware byte order,
		// so we better do that as well:
		result.order(ByteOrder.nativeOrder());
		return result;
	}

	private char[] toCharIndices (int count, int type, Buffer indices) {
		char[] result = new char[count];
		switch (type) {
		case GL_UNSIGNED_BYTE: {
			ByteBuffer byteBuffer = toByteBuffer(count, indices);
			byte[] array = byteBuffer.array();
			int offset = byteBuffer.arrayOffset();
			for (int i = 0; i < count; i++) {
				result[i] = (char)(0xff & array[offset + i]);
			}
		}
			break;
		case GL_UNSIGNED_SHORT: {
			CharBuffer charBuffer;
			if (indices instanceof CharBuffer) {
				charBuffer = (CharBuffer)indices;
			} else {
				ByteBuffer byteBuffer = toByteBuffer(count * 2, indices);
				charBuffer = byteBuffer.asCharBuffer();
			}
			int oldPosition = charBuffer.position();
			charBuffer.position(0);
			charBuffer.get(result);
			charBuffer.position(oldPosition);
		}
			break;
		default:
			// Don't throw an exception, because we don't want logging to
			// change the behavior.
			break;
		}
		return result;
	}

	private void doArrayElement (StringBuilder builder, boolean enabled, String name, PointerInfo pointer, int index) {
		if (!enabled) {
			return;
		}
		builder.append(" ");
		builder.append(name + ":{");
		if (pointer == null) {
			builder.append("undefined");
			return;
		}
		if (pointer.mStride < 0) {
			builder.append("invalid stride");
			return;
		}

		int stride = pointer.getStride();
		ByteBuffer byteBuffer = pointer.mTempByteBuffer;
		int size = pointer.mSize;
		int type = pointer.mType;
		int sizeofType = pointer.sizeof(type);
		int byteOffset = stride * index;
		for (int i = 0; i < size; i++) {
			if (i > 0) {
				builder.append(", ");
			}
			switch (type) {
			case GL_BYTE: {
				byte d = byteBuffer.get(byteOffset);
				builder.append(Integer.toString(d));
			}
				break;
			case GL_UNSIGNED_BYTE: {
				byte d = byteBuffer.get(byteOffset);
				builder.append(Integer.toString(0xff & d));
			}
				break;
			case GL_SHORT: {
				ShortBuffer shortBuffer = byteBuffer.asShortBuffer();
				short d = shortBuffer.get(byteOffset / 2);
				builder.append(Integer.toString(d));
			}
				break;
			case GL_FIXED: {
				IntBuffer intBuffer = byteBuffer.asIntBuffer();
				int d = intBuffer.get(byteOffset / 4);
				builder.append(Integer.toString(d));
			}
				break;
			case GL_FLOAT: {
				FloatBuffer intBuffer = byteBuffer.asFloatBuffer();
				float d = intBuffer.get(byteOffset / 4);
				builder.append(Float.toString(d));
			}
				break;
			default:
				builder.append("?");
				break;
			}
			byteOffset += sizeofType;
		}
		builder.append("}");
	}

	private void doElement (StringBuilder builder, int ordinal, int vertexIndex) {
		builder.append(" [" + ordinal + " : " + vertexIndex + "] =");
		doArrayElement(builder, mVertexArrayEnabled, "v", mVertexPointer, vertexIndex);
		doArrayElement(builder, mNormalArrayEnabled, "n", mNormalPointer, vertexIndex);
		doArrayElement(builder, mColorArrayEnabled, "c", mColorPointer, vertexIndex);
		doArrayElement(builder, mTextureCoordArrayEnabled, "t", mTexCoordPointer, vertexIndex);
		builder.append("\n");
		// Vertex
		// Normal
		// Color
		// TexCoord
	}

	private void bindArrays () {
		if (mColorArrayEnabled) mColorPointer.bindByteBuffer();
		if (mNormalArrayEnabled) mNormalPointer.bindByteBuffer();
		if (mTextureCoordArrayEnabled) mTexCoordPointer.bindByteBuffer();
		if (mVertexArrayEnabled) mVertexPointer.bindByteBuffer();
	}

	private void unbindArrays () {
		if (mColorArrayEnabled) mColorPointer.unbindByteBuffer();
		if (mNormalArrayEnabled) mNormalPointer.unbindByteBuffer();
		if (mTextureCoordArrayEnabled) mTexCoordPointer.unbindByteBuffer();
		if (mVertexArrayEnabled) mVertexPointer.unbindByteBuffer();
	}

	private void startLogIndices () {
		mStringBuilder = new StringBuilder();
		mStringBuilder.append("\n");
		bindArrays();
	}

	private void endLogIndices () {
		log(mStringBuilder.toString());
		unbindArrays();
	}

	// ---------------------------------------------------------------------
	// GL10 methods:

	public void glActiveTexture (int texture) {
		begin("glActiveTexture");
		arg("texture", texture);
		end();
		mgl.glActiveTexture(texture);
		checkError();
	}

	public void glAlphaFunc (int func, float ref) {
		begin("glAlphaFunc");
		arg("func", func);
		arg("ref", ref);
		end();
		mgl.glAlphaFunc(func, ref);
		checkError();
	}

	public void glAlphaFuncx (int func, int ref) {
		begin("glAlphaFuncx");
		arg("func", func);
		arg("ref", ref);
		end();
		mgl.glAlphaFuncx(func, ref);
		checkError();
	}

	public void glBindTexture (int target, int texture) {
		begin("glBindTexture");
		arg("target", getTextureTarget(target));
		arg("texture", texture);
		end();
		mgl.glBindTexture(target, texture);
		checkError();
	}

	public void glBlendFunc (int sfactor, int dfactor) {
		begin("glBlendFunc");
		arg("sfactor", getFactor(sfactor));
		arg("dfactor", getFactor(dfactor));
		end();

		mgl.glBlendFunc(sfactor, dfactor);
		checkError();
	}

	public void glClear (int mask) {
		begin("glClear");
		arg("mask", getClearBufferMask(mask));
		end();

		mgl.glClear(mask);
		checkError();
	}

	public void glClearColor (float red, float green, float blue, float alpha) {
		begin("glClearColor");
		arg("red", red);
		arg("green", green);
		arg("blue", blue);
		arg("alpha", alpha);
		end();

		mgl.glClearColor(red, green, blue, alpha);
		checkError();
	}

	public void glClearColorx (int red, int green, int blue, int alpha) {
		begin("glClearColor");
		arg("red", red);
		arg("green", green);
		arg("blue", blue);
		arg("alpha", alpha);
		end();

		mgl.glClearColorx(red, green, blue, alpha);
		checkError();
	}

	public void glClearDepthf (float depth) {
		begin("glClearDepthf");
		arg("depth", depth);
		end();

		mgl.glClearDepthf(depth);
		checkError();
	}

	public void glClearDepthx (int depth) {
		begin("glClearDepthx");
		arg("depth", depth);
		end();

		mgl.glClearDepthx(depth);
		checkError();
	}

	public void glClearStencil (int s) {
		begin("glClearStencil");
		arg("s", s);
		end();

		mgl.glClearStencil(s);
		checkError();
	}

	public void glClientActiveTexture (int texture) {
		begin("glClientActiveTexture");
		arg("texture", texture);
		end();

		mgl.glClientActiveTexture(texture);
		checkError();
	}

	public void glColor4f (float red, float green, float blue, float alpha) {
		begin("glColor4f");
		arg("red", red);
		arg("green", green);
		arg("blue", blue);
		arg("alpha", alpha);
		end();

		mgl.glColor4f(red, green, blue, alpha);
		checkError();
	}

	public void glColor4x (int red, int green, int blue, int alpha) {
		begin("glColor4x");
		arg("red", red);
		arg("green", green);
		arg("blue", blue);
		arg("alpha", alpha);
		end();

		mgl.glColor4x(red, green, blue, alpha);
		checkError();
	}

	public void glColorMask (boolean red, boolean green, boolean blue, boolean alpha) {
		begin("glColorMask");
		arg("red", red);
		arg("green", green);
		arg("blue", blue);
		arg("alpha", alpha);
		end();

		mgl.glColorMask(red, green, blue, alpha);
		checkError();
	}

	public void glColorPointer (int size, int type, int stride, Buffer pointer) {
		begin("glColorPointer");
		argPointer(size, type, stride, pointer);
		end();
		mColorPointer = new PointerInfo(size, type, stride, pointer);

		mgl.glColorPointer(size, type, stride, pointer);
		checkError();
	}

	public void glCompressedTexImage2D (int target, int level, int internalformat, int width, int height, int border,
		int imageSize, Buffer data) {
		begin("glCompressedTexImage2D");
		arg("target", getTextureTarget(target));
		arg("level", level);
		arg("internalformat", internalformat);
		arg("width", width);
		arg("height", height);
		arg("border", border);
		arg("imageSize", imageSize);
		arg("data", data.toString());
		end();

		mgl.glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data);
		checkError();
	}

	public void glCompressedTexSubImage2D (int target, int level, int xoffset, int yoffset, int width, int height, int format,
		int imageSize, Buffer data) {
		begin("glCompressedTexSubImage2D");
		arg("target", getTextureTarget(target));
		arg("level", level);
		arg("xoffset", xoffset);
		arg("yoffset", yoffset);
		arg("width", width);
		arg("height", height);
		arg("format", format);
		arg("imageSize", imageSize);
		arg("data", data.toString());
		end();

		mgl.glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data);
		checkError();
	}

	public void glCopyTexImage2D (int target, int level, int internalformat, int x, int y, int width, int height, int border) {
		begin("glCopyTexImage2D");
		arg("target", getTextureTarget(target));
		arg("level", level);
		arg("internalformat", internalformat);
		arg("x", x);
		arg("y", y);
		arg("width", width);
		arg("height", height);
		arg("border", border);
		end();

		mgl.glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
		checkError();
	}

	public void glCopyTexSubImage2D (int target, int level, int xoffset, int yoffset, int x, int y, int width, int height) {
		begin("glCopyTexSubImage2D");
		arg("target", getTextureTarget(target));
		arg("level", level);
		arg("xoffset", xoffset);
		arg("yoffset", yoffset);
		arg("x", x);
		arg("y", y);
		arg("width", width);
		arg("height", height);
		end();

		mgl.glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
		checkError();
	}

	public void glCullFace (int mode) {
		begin("glCullFace");
		arg("mode", mode);
		end();

		mgl.glCullFace(mode);
		checkError();
	}

	public void glDeleteTextures (int n, int[] textures, int offset) {
		begin("glDeleteTextures");
		arg("n", n);
		arg("textures", n, textures, offset);
		arg("offset", offset);
		end();

		mgl.glDeleteTextures(n, textures, offset);
		checkError();
	}

	public void glDeleteTextures (int n, IntBuffer textures) {
		begin("glDeleteTextures");
		arg("n", n);
		arg("textures", n, textures);
		end();

		mgl.glDeleteTextures(n, textures);
		checkError();
	}

	public void glDepthFunc (int func) {
		begin("glDepthFunc");
		arg("func", func);
		end();

		mgl.glDepthFunc(func);
		checkError();
	}

	public void glDepthMask (boolean flag) {
		begin("glDepthMask");
		arg("flag", flag);
		end();

		mgl.glDepthMask(flag);
		checkError();
	}

	public void glDepthRangef (float near, float far) {
		begin("glDepthRangef");
		arg("near", near);
		arg("far", far);
		end();

		mgl.glDepthRangef(near, far);
		checkError();
	}

	public void glDepthRangex (int near, int far) {
		begin("glDepthRangex");
		arg("near", near);
		arg("far", far);
		end();

		mgl.glDepthRangex(near, far);
		checkError();
	}

	public void glDisable (int cap) {
		begin("glDisable");
		arg("cap", getCap(cap));
		end();

		mgl.glDisable(cap);
		checkError();
	}

	public void glDisableClientState (int array) {
		begin("glDisableClientState");
		arg("array", getClientState(array));
		end();

		switch (array) {
		case GL_COLOR_ARRAY:
			mColorArrayEnabled = false;
			break;
		case GL_NORMAL_ARRAY:
			mNormalArrayEnabled = false;
			break;
		case GL_TEXTURE_COORD_ARRAY:
			mTextureCoordArrayEnabled = false;
			break;
		case GL_VERTEX_ARRAY:
			mVertexArrayEnabled = false;
			break;
		}
		mgl.glDisableClientState(array);
		checkError();
	}

	public void glDrawArrays (int mode, int first, int count) {
		begin("glDrawArrays");
		arg("mode", mode);
		arg("first", first);
		arg("count", count);
		startLogIndices();
		for (int i = 0; i < count; i++) {
			doElement(mStringBuilder, i, first + i);
		}
		endLogIndices();
		end();

		mgl.glDrawArrays(mode, first, count);
		checkError();
	}

	public void glDrawElements (int mode, int count, int type, Buffer indices) {
		begin("glDrawElements");
		arg("mode", getBeginMode(mode));
		arg("count", count);
		arg("type", getIndexType(type));
		char[] indexArray = toCharIndices(count, type, indices);
		int indexArrayLength = indexArray.length;
		startLogIndices();
		for (int i = 0; i < indexArrayLength; i++) {
			doElement(mStringBuilder, i, indexArray[i]);
		}
		endLogIndices();
		end();

		mgl.glDrawElements(mode, count, type, indices);
		checkError();
	}

	public void glEnable (int cap) {
		begin("glEnable");
		arg("cap", getCap(cap));
		end();

		mgl.glEnable(cap);
		checkError();
	}

	public void glEnableClientState (int array) {
		begin("glEnableClientState");
		arg("array", getClientState(array));
		end();

		switch (array) {
		case GL_COLOR_ARRAY:
			mColorArrayEnabled = true;
			break;
		case GL_NORMAL_ARRAY:
			mNormalArrayEnabled = true;
			break;
		case GL_TEXTURE_COORD_ARRAY:
			mTextureCoordArrayEnabled = true;
			break;
		case GL_VERTEX_ARRAY:
			mVertexArrayEnabled = true;
			break;
		}
		mgl.glEnableClientState(array);
		checkError();
	}

	public void glFinish () {
		begin("glFinish");
		end();

		mgl.glFinish();
		checkError();
	}

	public void glFlush () {
		begin("glFlush");
		end();

		mgl.glFlush();
		checkError();
	}

	public void glFogf (int pname, float param) {
		begin("glFogf");
		arg("pname", pname);
		arg("param", param);
		end();

		mgl.glFogf(pname, param);
		checkError();
	}

	public void glFogfv (int pname, float[] params, int offset) {
		begin("glFogfv");
		arg("pname", getFogPName(pname));
		arg("params", getFogParamCount(pname), params, offset);
		arg("offset", offset);
		end();

		mgl.glFogfv(pname, params, offset);
		checkError();
	}

	public void glFogfv (int pname, FloatBuffer params) {
		begin("glFogfv");
		arg("pname", getFogPName(pname));
		arg("params", getFogParamCount(pname), params);
		end();

		mgl.glFogfv(pname, params);
		checkError();
	}

	public void glFogx (int pname, int param) {
		begin("glFogx");
		arg("pname", getFogPName(pname));
		arg("param", param);
		end();

		mgl.glFogx(pname, param);
		checkError();
	}

	public void glFogxv (int pname, int[] params, int offset) {
		begin("glFogxv");
		arg("pname", getFogPName(pname));
		arg("params", getFogParamCount(pname), params, offset);
		arg("offset", offset);
		end();

		mgl.glFogxv(pname, params, offset);
		checkError();
	}

	public void glFogxv (int pname, IntBuffer params) {
		begin("glFogxv");
		arg("pname", getFogPName(pname));
		arg("params", getFogParamCount(pname), params);
		end();

		mgl.glFogxv(pname, params);
		checkError();
	}

	public void glFrontFace (int mode) {
		begin("glFrontFace");
		arg("mode", mode);
		end();

		mgl.glFrontFace(mode);
		checkError();
	}

	public void glFrustumf (float left, float right, float bottom, float top, float near, float far) {
		begin("glFrustumf");
		arg("left", left);
		arg("right", right);
		arg("bottom", bottom);
		arg("top", top);
		arg("near", near);
		arg("far", far);
		end();

		mgl.glFrustumf(left, right, bottom, top, near, far);
		checkError();
	}

	public void glFrustumx (int left, int right, int bottom, int top, int near, int far) {
		begin("glFrustumx");
		arg("left", left);
		arg("right", right);
		arg("bottom", bottom);
		arg("top", top);
		arg("near", near);
		arg("far", far);
		end();

		mgl.glFrustumx(left, right, bottom, top, near, far);
		checkError();
	}

	public void glGenTextures (int n, int[] textures, int offset) {
		begin("glGenTextures");
		arg("n", n);
		arg("textures", Arrays.toString(textures));
		arg("offset", offset);

		mgl.glGenTextures(n, textures, offset);

		returns(toString(n, FORMAT_INT, textures, offset));

		checkError();
	}

	public void glGenTextures (int n, IntBuffer textures) {
		begin("glGenTextures");
		arg("n", n);
		arg("textures", textures.toString());

		mgl.glGenTextures(n, textures);

		returns(toString(n, FORMAT_INT, textures));

		checkError();
	}

	public int glGetError () {
		begin("glGetError");

		int result = mgl.glGetError();

		returns(result);

		return result;
	}

	public void glGetIntegerv (int pname, int[] params, int offset) {
		begin("glGetIntegerv");
		arg("pname", getIntegerStateName(pname));
		arg("params", Arrays.toString(params));
		arg("offset", offset);

		mgl.glGetIntegerv(pname, params, offset);

		returns(toString(getIntegerStateSize(pname), getIntegerStateFormat(pname), params, offset));

		checkError();
	}

	public void glGetIntegerv (int pname, IntBuffer params) {
		begin("glGetIntegerv");
		arg("pname", getIntegerStateName(pname));
		arg("params", params.toString());

		mgl.glGetIntegerv(pname, params);

		returns(toString(getIntegerStateSize(pname), getIntegerStateFormat(pname), params));

		checkError();
	}

	public String glGetString (int name) {
		begin("glGetString");
		arg("name", name);

		String result = mgl.glGetString(name);

		returns(result);

		checkError();
		return result;
	}

	public void glHint (int target, int mode) {
		begin("glHint");
		arg("target", getHintTarget(target));
		arg("mode", getHintMode(mode));
		end();

		mgl.glHint(target, mode);
		checkError();
	}

	public void glLightModelf (int pname, float param) {
		begin("glLightModelf");
		arg("pname", getLightModelPName(pname));
		arg("param", param);
		end();

		mgl.glLightModelf(pname, param);
		checkError();
	}

	public void glLightModelfv (int pname, float[] params, int offset) {
		begin("glLightModelfv");
		arg("pname", getLightModelPName(pname));
		arg("params", getLightModelParamCount(pname), params, offset);
		arg("offset", offset);
		end();

		mgl.glLightModelfv(pname, params, offset);
		checkError();
	}

	public void glLightModelfv (int pname, FloatBuffer params) {
		begin("glLightModelfv");
		arg("pname", getLightModelPName(pname));
		arg("params", getLightModelParamCount(pname), params);
		end();

		mgl.glLightModelfv(pname, params);
		checkError();
	}

	public void glLightModelx (int pname, int param) {
		begin("glLightModelx");
		arg("pname", getLightModelPName(pname));
		arg("param", param);
		end();

		mgl.glLightModelx(pname, param);
		checkError();
	}

	public void glLightModelxv (int pname, int[] params, int offset) {
		begin("glLightModelxv");
		arg("pname", getLightModelPName(pname));
		arg("params", getLightModelParamCount(pname), params, offset);
		arg("offset", offset);
		end();

		mgl.glLightModelxv(pname, params, offset);
		checkError();
	}

	public void glLightModelxv (int pname, IntBuffer params) {
		begin("glLightModelfv");
		arg("pname", getLightModelPName(pname));
		arg("params", getLightModelParamCount(pname), params);
		end();

		mgl.glLightModelxv(pname, params);
		checkError();
	}

	public void glLightf (int light, int pname, float param) {
		begin("glLightf");
		arg("light", getLightName(light));
		arg("pname", getLightPName(pname));
		arg("param", param);
		end();

		mgl.glLightf(light, pname, param);
		checkError();
	}

	public void glLightfv (int light, int pname, float[] params, int offset) {
		begin("glLightfv");
		arg("light", getLightName(light));
		arg("pname", getLightPName(pname));
		arg("params", getLightParamCount(pname), params, offset);
		arg("offset", offset);
		end();

		mgl.glLightfv(light, pname, params, offset);
		checkError();
	}

	public void glLightfv (int light, int pname, FloatBuffer params) {
		begin("glLightfv");
		arg("light", getLightName(light));
		arg("pname", getLightPName(pname));
		arg("params", getLightParamCount(pname), params);
		end();

		mgl.glLightfv(light, pname, params);
		checkError();
	}

	public void glLightx (int light, int pname, int param) {
		begin("glLightx");
		arg("light", getLightName(light));
		arg("pname", getLightPName(pname));
		arg("param", param);
		end();

		mgl.glLightx(light, pname, param);
		checkError();
	}

	public void glLightxv (int light, int pname, int[] params, int offset) {
		begin("glLightxv");
		arg("light", getLightName(light));
		arg("pname", getLightPName(pname));
		arg("params", getLightParamCount(pname), params, offset);
		arg("offset", offset);
		end();

		mgl.glLightxv(light, pname, params, offset);
		checkError();
	}

	public void glLightxv (int light, int pname, IntBuffer params) {
		begin("glLightxv");
		arg("light", getLightName(light));
		arg("pname", getLightPName(pname));
		arg("params", getLightParamCount(pname), params);
		end();

		mgl.glLightxv(light, pname, params);
		checkError();
	}

	public void glLineWidth (float width) {
		begin("glLineWidth");
		arg("width", width);
		end();

		mgl.glLineWidth(width);
		checkError();
	}

	public void glLineWidthx (int width) {
		begin("glLineWidthx");
		arg("width", width);
		end();

		mgl.glLineWidthx(width);
		checkError();
	}

	public void glLoadIdentity () {
		begin("glLoadIdentity");
		end();

		mgl.glLoadIdentity();
		checkError();
	}

	public void glLoadMatrixf (float[] m, int offset) {
		begin("glLoadMatrixf");
		arg("m", 16, m, offset);
		arg("offset", offset);
		end();

		mgl.glLoadMatrixf(m, offset);
		checkError();
	}

	public void glLoadMatrixf (FloatBuffer m) {
		begin("glLoadMatrixf");
		arg("m", 16, m);
		end();

		mgl.glLoadMatrixf(m);
		checkError();
	}

	public void glLoadMatrixx (int[] m, int offset) {
		begin("glLoadMatrixx");
		arg("m", 16, m, offset);
		arg("offset", offset);
		end();

		mgl.glLoadMatrixx(m, offset);
		checkError();
	}

	public void glLoadMatrixx (IntBuffer m) {
		begin("glLoadMatrixx");
		arg("m", 16, m);
		end();

		mgl.glLoadMatrixx(m);
		checkError();
	}

	public void glLogicOp (int opcode) {
		begin("glLogicOp");
		arg("opcode", opcode);
		end();

		mgl.glLogicOp(opcode);
		checkError();
	}

	public void glMaterialf (int face, int pname, float param) {
		begin("glMaterialf");
		arg("face", getFaceName(face));
		arg("pname", getMaterialPName(pname));
		arg("param", param);
		end();

		mgl.glMaterialf(face, pname, param);
		checkError();
	}

	public void glMaterialfv (int face, int pname, float[] params, int offset) {
		begin("glMaterialfv");
		arg("face", getFaceName(face));
		arg("pname", getMaterialPName(pname));
		arg("params", getMaterialParamCount(pname), params, offset);
		arg("offset", offset);
		end();

		mgl.glMaterialfv(face, pname, params, offset);
		checkError();
	}

	public void glMaterialfv (int face, int pname, FloatBuffer params) {
		begin("glMaterialfv");
		arg("face", getFaceName(face));
		arg("pname", getMaterialPName(pname));
		arg("params", getMaterialParamCount(pname), params);
		end();

		mgl.glMaterialfv(face, pname, params);
		checkError();
	}

	public void glMaterialx (int face, int pname, int param) {
		begin("glMaterialx");
		arg("face", getFaceName(face));
		arg("pname", getMaterialPName(pname));
		arg("param", param);
		end();

		mgl.glMaterialx(face, pname, param);
		checkError();
	}

	public void glMaterialxv (int face, int pname, int[] params, int offset) {
		begin("glMaterialxv");
		arg("face", getFaceName(face));
		arg("pname", getMaterialPName(pname));
		arg("params", getMaterialParamCount(pname), params, offset);
		arg("offset", offset);
		end();

		mgl.glMaterialxv(face, pname, params, offset);
		checkError();
	}

	public void glMaterialxv (int face, int pname, IntBuffer params) {
		begin("glMaterialxv");
		arg("face", getFaceName(face));
		arg("pname", getMaterialPName(pname));
		arg("params", getMaterialParamCount(pname), params);
		end();

		mgl.glMaterialxv(face, pname, params);
		checkError();
	}

	public void glMatrixMode (int mode) {
		begin("glMatrixMode");
		arg("mode", getMatrixMode(mode));
		end();

		mgl.glMatrixMode(mode);
		checkError();
	}

	public void glMultMatrixf (float[] m, int offset) {
		begin("glMultMatrixf");
		arg("m", 16, m, offset);
		arg("offset", offset);
		end();

		mgl.glMultMatrixf(m, offset);
		checkError();
	}

	public void glMultMatrixf (FloatBuffer m) {
		begin("glMultMatrixf");
		arg("m", 16, m);
		end();

		mgl.glMultMatrixf(m);
		checkError();
	}

	public void glMultMatrixx (int[] m, int offset) {
		begin("glMultMatrixx");
		arg("m", 16, m, offset);
		arg("offset", offset);
		end();

		mgl.glMultMatrixx(m, offset);
		checkError();
	}

	public void glMultMatrixx (IntBuffer m) {
		begin("glMultMatrixx");
		arg("m", 16, m);
		end();

		mgl.glMultMatrixx(m);
		checkError();
	}

	public void glMultiTexCoord4f (int target, float s, float t, float r, float q) {
		begin("glMultiTexCoord4f");
		arg("target", target);
		arg("s", s);
		arg("t", t);
		arg("r", r);
		arg("q", q);
		end();

		mgl.glMultiTexCoord4f(target, s, t, r, q);
		checkError();
	}

	public void glMultiTexCoord4x (int target, int s, int t, int r, int q) {
		begin("glMultiTexCoord4x");
		arg("target", target);
		arg("s", s);
		arg("t", t);
		arg("r", r);
		arg("q", q);
		end();

		mgl.glMultiTexCoord4x(target, s, t, r, q);
		checkError();
	}

	public void glNormal3f (float nx, float ny, float nz) {
		begin("glNormal3f");
		arg("nx", nx);
		arg("ny", ny);
		arg("nz", nz);
		end();

		mgl.glNormal3f(nx, ny, nz);
		checkError();
	}

	public void glNormal3x (int nx, int ny, int nz) {
		begin("glNormal3x");
		arg("nx", nx);
		arg("ny", ny);
		arg("nz", nz);
		end();

		mgl.glNormal3x(nx, ny, nz);
		checkError();
	}

	public void glNormalPointer (int type, int stride, Buffer pointer) {
		begin("glNormalPointer");
		arg("type", type);
		arg("stride", stride);
		arg("pointer", pointer.toString());
		end();
		mNormalPointer = new PointerInfo(3, type, stride, pointer);

		mgl.glNormalPointer(type, stride, pointer);
		checkError();
	}

	public void glOrthof (float left, float right, float bottom, float top, float near, float far) {
		begin("glOrthof");
		arg("left", left);
		arg("right", right);
		arg("bottom", bottom);
		arg("top", top);
		arg("near", near);
		arg("far", far);
		end();

		mgl.glOrthof(left, right, bottom, top, near, far);
		checkError();
	}

	public void glOrthox (int left, int right, int bottom, int top, int near, int far) {
		begin("glOrthox");
		arg("left", left);
		arg("right", right);
		arg("bottom", bottom);
		arg("top", top);
		arg("near", near);
		arg("far", far);
		end();

		mgl.glOrthox(left, right, bottom, top, near, far);
		checkError();
	}

	public void glPixelStorei (int pname, int param) {
		begin("glPixelStorei");
		arg("pname", pname);
		arg("param", param);
		end();

		mgl.glPixelStorei(pname, param);
		checkError();
	}

	public void glPointSize (float size) {
		begin("glPointSize");
		arg("size", size);
		end();

		mgl.glPointSize(size);
		checkError();
	}

	public void glPointSizex (int size) {
		begin("glPointSizex");
		arg("size", size);
		end();

		mgl.glPointSizex(size);
		checkError();
	}

	public void glPolygonOffset (float factor, float units) {
		begin("glPolygonOffset");
		arg("factor", factor);
		arg("units", units);
		end();
		mgl.glPolygonOffset(factor, units);
		checkError();
	}

	public void glPolygonOffsetx (int factor, int units) {
		begin("glPolygonOffsetx");
		arg("factor", factor);
		arg("units", units);
		end();

		mgl.glPolygonOffsetx(factor, units);
		checkError();
	}

	public void glPopMatrix () {
		begin("glPopMatrix");
		end();

		mgl.glPopMatrix();
		checkError();
	}

	public void glPushMatrix () {
		begin("glPushMatrix");
		end();

		mgl.glPushMatrix();
		checkError();
	}

	public void glReadPixels (int x, int y, int width, int height, int format, int type, Buffer pixels) {
		begin("glReadPixels");
		arg("x", x);
		arg("y", y);
		arg("width", width);
		arg("height", height);
		arg("format", format);
		arg("type", type);
		arg("pixels", pixels.toString());
		end();

		mgl.glReadPixels(x, y, width, height, format, type, pixels);
		checkError();
	}

	public void glRotatef (float angle, float x, float y, float z) {
		begin("glRotatef");
		arg("angle", angle);
		arg("x", x);
		arg("y", y);
		arg("z", z);
		end();

		mgl.glRotatef(angle, x, y, z);
		checkError();
	}

	public void glRotatex (int angle, int x, int y, int z) {
		begin("glRotatex");
		arg("angle", angle);
		arg("x", x);
		arg("y", y);
		arg("z", z);
		end();

		mgl.glRotatex(angle, x, y, z);
		checkError();
	}

	public void glSampleCoverage (float value, boolean invert) {
		begin("glSampleCoveragex");
		arg("value", value);
		arg("invert", invert);
		end();

		mgl.glSampleCoverage(value, invert);
		checkError();
	}

	public void glSampleCoveragex (int value, boolean invert) {
		begin("glSampleCoveragex");
		arg("value", value);
		arg("invert", invert);
		end();

		mgl.glSampleCoveragex(value, invert);
		checkError();
	}

	public void glScalef (float x, float y, float z) {
		begin("glScalef");
		arg("x", x);
		arg("y", y);
		arg("z", z);
		end();

		mgl.glScalef(x, y, z);
		checkError();
	}

	public void glScalex (int x, int y, int z) {
		begin("glScalex");
		arg("x", x);
		arg("y", y);
		arg("z", z);
		end();

		mgl.glScalex(x, y, z);
		checkError();
	}

	public void glScissor (int x, int y, int width, int height) {
		begin("glScissor");
		arg("x", x);
		arg("y", y);
		arg("width", width);
		arg("height", height);
		end();

		mgl.glScissor(x, y, width, height);
		checkError();
	}

	public void glShadeModel (int mode) {
		begin("glShadeModel");
		arg("mode", getShadeModel(mode));
		end();

		mgl.glShadeModel(mode);
		checkError();
	}

	public void glStencilFunc (int func, int ref, int mask) {
		begin("glStencilFunc");
		arg("func", func);
		arg("ref", ref);
		arg("mask", mask);
		end();

		mgl.glStencilFunc(func, ref, mask);
		checkError();
	}

	public void glStencilMask (int mask) {
		begin("glStencilMask");
		arg("mask", mask);
		end();

		mgl.glStencilMask(mask);
		checkError();
	}

	public void glStencilOp (int fail, int zfail, int zpass) {
		begin("glStencilOp");
		arg("fail", fail);
		arg("zfail", zfail);
		arg("zpass", zpass);
		end();

		mgl.glStencilOp(fail, zfail, zpass);
		checkError();
	}

	public void glTexCoordPointer (int size, int type, int stride, Buffer pointer) {
		begin("glTexCoordPointer");
		argPointer(size, type, stride, pointer);
		end();
		mTexCoordPointer = new PointerInfo(size, type, stride, pointer);

		mgl.glTexCoordPointer(size, type, stride, pointer);
		checkError();
	}

	public void glTexEnvf (int target, int pname, float param) {
		begin("glTexEnvf");
		arg("target", getTextureEnvTarget(target));
		arg("pname", getTextureEnvPName(pname));
		arg("param", getTextureEnvParamName(param));
		end();

		mgl.glTexEnvf(target, pname, param);
		checkError();
	}

	public void glTexEnvfv (int target, int pname, float[] params, int offset) {
		begin("glTexEnvfv");
		arg("target", getTextureEnvTarget(target));
		arg("pname", getTextureEnvPName(pname));
		arg("params", getTextureEnvParamCount(pname), params, offset);
		arg("offset", offset);
		end();

		mgl.glTexEnvfv(target, pname, params, offset);
		checkError();
	}

	public void glTexEnvfv (int target, int pname, FloatBuffer params) {
		begin("glTexEnvfv");
		arg("target", getTextureEnvTarget(target));
		arg("pname", getTextureEnvPName(pname));
		arg("params", getTextureEnvParamCount(pname), params);
		end();

		mgl.glTexEnvfv(target, pname, params);
		checkError();
	}

	public void glTexEnvx (int target, int pname, int param) {
		begin("glTexEnvx");
		arg("target", getTextureEnvTarget(target));
		arg("pname", getTextureEnvPName(pname));
		arg("param", param);
		end();

		mgl.glTexEnvx(target, pname, param);
		checkError();
	}

	public void glTexEnvxv (int target, int pname, int[] params, int offset) {
		begin("glTexEnvxv");
		arg("target", getTextureEnvTarget(target));
		arg("pname", getTextureEnvPName(pname));
		arg("params", getTextureEnvParamCount(pname), params, offset);
		arg("offset", offset);
		end();

		mgl.glTexEnvxv(target, pname, params, offset);
		checkError();
	}

	public void glTexEnvxv (int target, int pname, IntBuffer params) {
		begin("glTexEnvxv");
		arg("target", getTextureEnvTarget(target));
		arg("pname", getTextureEnvPName(pname));
		arg("params", getTextureEnvParamCount(pname), params);
		end();

		mgl.glTexEnvxv(target, pname, params);
		checkError();
	}

	public void glTexImage2D (int target, int level, int internalformat, int width, int height, int border, int format, int type,
		Buffer pixels) {
		begin("glTexImage2D");
		arg("target", target);
		arg("level", level);
		arg("internalformat", internalformat);
		arg("width", width);
		arg("height", height);
		arg("border", border);
		arg("format", format);
		arg("type", type);
		arg("pixels", pixels.toString());
		end();

		mgl.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
		checkError();
	}

	public void glTexParameterf (int target, int pname, float param) {
		begin("glTexParameterf");
		arg("target", getTextureTarget(target));
		arg("pname", getTexturePName(pname));
		arg("param", getTextureParamName(param));
		end();

		mgl.glTexParameterf(target, pname, param);
		checkError();
	}

	public void glTexParameterx (int target, int pname, int param) {
		begin("glTexParameterx");
		arg("target", getTextureTarget(target));
		arg("pname", getTexturePName(pname));
		arg("param", param);
		end();

		mgl.glTexParameterx(target, pname, param);
		checkError();
	}

	public void glTexParameteriv (int target, int pname, int[] params, int offset) {
		begin("glTexParameteriv");
		arg("target", getTextureTarget(target));
		arg("pname", getTexturePName(pname));
		arg("params", 4, params, offset);
		end();

		mgl11.glTexParameteriv(target, pname, params, offset);
		checkError();
	}

	public void glTexParameteriv (int target, int pname, IntBuffer params) {
		begin("glTexParameteriv");
		arg("target", getTextureTarget(target));
		arg("pname", getTexturePName(pname));
		arg("params", 4, params);
		end();

		mgl11.glTexParameteriv(target, pname, params);
		checkError();
	}

	public void glTexSubImage2D (int target, int level, int xoffset, int yoffset, int width, int height, int format, int type,
		Buffer pixels) {
		begin("glTexSubImage2D");
		arg("target", getTextureTarget(target));
		arg("level", level);
		arg("xoffset", xoffset);
		arg("yoffset", yoffset);
		arg("width", width);
		arg("height", height);
		arg("format", format);
		arg("type", type);
		arg("pixels", pixels.toString());
		end();
		mgl.glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
		checkError();
	}

	public void glTranslatef (float x, float y, float z) {
		begin("glTranslatef");
		arg("x", x);
		arg("y", y);
		arg("z", z);
		end();
		mgl.glTranslatef(x, y, z);
		checkError();
	}

	public void glTranslatex (int x, int y, int z) {
		begin("glTranslatex");
		arg("x", x);
		arg("y", y);
		arg("z", z);
		end();
		mgl.glTranslatex(x, y, z);
		checkError();
	}

	public void glVertexPointer (int size, int type, int stride, Buffer pointer) {
		begin("glVertexPointer");
		argPointer(size, type, stride, pointer);
		end();
		mVertexPointer = new PointerInfo(size, type, stride, pointer);
		mgl.glVertexPointer(size, type, stride, pointer);
		checkError();
	}

	public void glViewport (int x, int y, int width, int height) {
		begin("glViewport");
		arg("x", x);
		arg("y", y);
		arg("width", width);
		arg("height", height);
		end();
		mgl.glViewport(x, y, width, height);
		checkError();
	}

	public void glClipPlanef (int plane, float[] equation, int offset) {
		begin("glClipPlanef");
		arg("plane", plane);
		arg("equation", 4, equation, offset);
		arg("offset", offset);
		end();
		mgl11.glClipPlanef(plane, equation, offset);
		checkError();
	}

	public void glClipPlanef (int plane, FloatBuffer equation) {
		begin("glClipPlanef");
		arg("plane", plane);
		arg("equation", 4, equation);
		end();
		mgl11.glClipPlanef(plane, equation);
		checkError();
	}

	public void glClipPlanex (int plane, int[] equation, int offset) {
		begin("glClipPlanex");
		arg("plane", plane);
		arg("equation", 4, equation, offset);
		arg("offset", offset);
		end();
		mgl11.glClipPlanex(plane, equation, offset);
		checkError();
	}

	public void glClipPlanex (int plane, IntBuffer equation) {
		begin("glClipPlanef");
		arg("plane", plane);
		arg("equation", 4, equation);
		end();
		mgl11.glClipPlanex(plane, equation);
		checkError();
	}

	// Draw Texture Extension

	public void glDrawTexfOES (float x, float y, float z, float width, float height) {
		begin("glDrawTexfOES");
		arg("x", x);
		arg("y", y);
		arg("z", z);
		arg("width", width);
		arg("height", height);
		end();
		mgl11Ext.glDrawTexfOES(x, y, z, width, height);
		checkError();
	}

	public void glDrawTexfvOES (float[] coords, int offset) {
		begin("glDrawTexfvOES");
		arg("coords", 5, coords, offset);
		arg("offset", offset);
		end();
		mgl11Ext.glDrawTexfvOES(coords, offset);
		checkError();
	}

	public void glDrawTexfvOES (FloatBuffer coords) {
		begin("glDrawTexfvOES");
		arg("coords", 5, coords);
		end();
		mgl11Ext.glDrawTexfvOES(coords);
		checkError();
	}

	public void glDrawTexiOES (int x, int y, int z, int width, int height) {
		begin("glDrawTexiOES");
		arg("x", x);
		arg("y", y);
		arg("z", z);
		arg("width", width);
		arg("height", height);
		end();
		mgl11Ext.glDrawTexiOES(x, y, z, width, height);
		checkError();
	}

	public void glDrawTexivOES (int[] coords, int offset) {
		begin("glDrawTexivOES");
		arg("coords", 5, coords, offset);
		arg("offset", offset);
		end();
		mgl11Ext.glDrawTexivOES(coords, offset);
		checkError();
	}

	public void glDrawTexivOES (IntBuffer coords) {
		begin("glDrawTexivOES");
		arg("coords", 5, coords);
		end();
		mgl11Ext.glDrawTexivOES(coords);
		checkError();
	}

	public void glDrawTexsOES (short x, short y, short z, short width, short height) {
		begin("glDrawTexsOES");
		arg("x", x);
		arg("y", y);
		arg("z", z);
		arg("width", width);
		arg("height", height);
		end();
		mgl11Ext.glDrawTexsOES(x, y, z, width, height);
		checkError();
	}

	public void glDrawTexsvOES (short[] coords, int offset) {
		begin("glDrawTexsvOES");
		arg("coords", 5, coords, offset);
		arg("offset", offset);
		end();
		mgl11Ext.glDrawTexsvOES(coords, offset);
		checkError();
	}

	public void glDrawTexsvOES (ShortBuffer coords) {
		begin("glDrawTexsvOES");
		arg("coords", 5, coords);
		end();
		mgl11Ext.glDrawTexsvOES(coords);
		checkError();
	}

	public void glDrawTexxOES (int x, int y, int z, int width, int height) {
		begin("glDrawTexxOES");
		arg("x", x);
		arg("y", y);
		arg("z", z);
		arg("width", width);
		arg("height", height);
		end();
		mgl11Ext.glDrawTexxOES(x, y, z, width, height);
		checkError();
	}

	public void glDrawTexxvOES (int[] coords, int offset) {
		begin("glDrawTexxvOES");
		arg("coords", 5, coords, offset);
		arg("offset", offset);
		end();
		mgl11Ext.glDrawTexxvOES(coords, offset);
		checkError();
	}

	public void glDrawTexxvOES (IntBuffer coords) {
		begin("glDrawTexxvOES");
		arg("coords", 5, coords);
		end();
		mgl11Ext.glDrawTexxvOES(coords);
		checkError();
	}

	public int glQueryMatrixxOES (int[] mantissa, int mantissaOffset, int[] exponent, int exponentOffset) {
		begin("glQueryMatrixxOES");
		arg("mantissa", Arrays.toString(mantissa));
		arg("exponent", Arrays.toString(exponent));
		end();
		int valid = mgl10Ext.glQueryMatrixxOES(mantissa, mantissaOffset, exponent, exponentOffset);
		returns(toString(16, FORMAT_FIXED, mantissa, mantissaOffset));
		returns(toString(16, FORMAT_INT, exponent, exponentOffset));
		checkError();
		return valid;
	}

	public int glQueryMatrixxOES (IntBuffer mantissa, IntBuffer exponent) {
		begin("glQueryMatrixxOES");
		arg("mantissa", mantissa.toString());
		arg("exponent", exponent.toString());
		end();
		int valid = mgl10Ext.glQueryMatrixxOES(mantissa, exponent);
		returns(toString(16, FORMAT_FIXED, mantissa));
		returns(toString(16, FORMAT_INT, exponent));
		checkError();
		return valid;
	}

	// Unsupported GL11 methods

	public void glBindBuffer (int target, int buffer) {
		throw new UnsupportedOperationException();
	}

	public void glBufferData (int target, int size, Buffer data, int usage) {
		throw new UnsupportedOperationException();
	}

	public void glBufferSubData (int target, int offset, int size, Buffer data) {
		throw new UnsupportedOperationException();
	}

	public void glColor4ub (byte red, byte green, byte blue, byte alpha) {
		throw new UnsupportedOperationException();
	}

	public void glDeleteBuffers (int n, int[] buffers, int offset) {
		throw new UnsupportedOperationException();
	}

	public void glDeleteBuffers (int n, IntBuffer buffers) {
		throw new UnsupportedOperationException();
	}

	public void glGenBuffers (int n, int[] buffers, int offset) {
		throw new UnsupportedOperationException();
	}

	public void glGenBuffers (int n, IntBuffer buffers) {
		throw new UnsupportedOperationException();
	}

	public void glGetBooleanv (int pname, boolean[] params, int offset) {
		throw new UnsupportedOperationException();
	}

	public void glGetBooleanv (int pname, IntBuffer params) {
		throw new UnsupportedOperationException();
	}

	public void glGetBufferParameteriv (int target, int pname, int[] params, int offset) {
		throw new UnsupportedOperationException();
	}

	public void glGetBufferParameteriv (int target, int pname, IntBuffer params) {
		throw new UnsupportedOperationException();
	}

	public void glGetClipPlanef (int pname, float[] eqn, int offset) {
		throw new UnsupportedOperationException();
	}

	public void glGetClipPlanef (int pname, FloatBuffer eqn) {
		throw new UnsupportedOperationException();
	}

	public void glGetClipPlanex (int pname, int[] eqn, int offset) {
		throw new UnsupportedOperationException();
	}

	public void glGetClipPlanex (int pname, IntBuffer eqn) {
		throw new UnsupportedOperationException();
	}

	public void glGetFixedv (int pname, int[] params, int offset) {
		throw new UnsupportedOperationException();
	}

	public void glGetFixedv (int pname, IntBuffer params) {
		throw new UnsupportedOperationException();
	}

	public void glGetFloatv (int pname, float[] params, int offset) {
		throw new UnsupportedOperationException();
	}

	public void glGetFloatv (int pname, FloatBuffer params) {
		throw new UnsupportedOperationException();
	}

	public void glGetLightfv (int light, int pname, float[] params, int offset) {
		throw new UnsupportedOperationException();
	}

	public void glGetLightfv (int light, int pname, FloatBuffer params) {
		throw new UnsupportedOperationException();
	}

	public void glGetLightxv (int light, int pname, int[] params, int offset) {
		throw new UnsupportedOperationException();
	}

	public void glGetLightxv (int light, int pname, IntBuffer params) {
		throw new UnsupportedOperationException();
	}

	public void glGetMaterialfv (int face, int pname, float[] params, int offset) {
		throw new UnsupportedOperationException();
	}

	public void glGetMaterialfv (int face, int pname, FloatBuffer params) {
		throw new UnsupportedOperationException();
	}

	public void glGetMaterialxv (int face, int pname, int[] params, int offset) {
		throw new UnsupportedOperationException();
	}

	public void glGetMaterialxv (int face, int pname, IntBuffer params) {
		throw new UnsupportedOperationException();
	}

	public void glGetTexEnviv (int env, int pname, int[] params, int offset) {
		throw new UnsupportedOperationException();
	}

	public void glGetTexEnviv (int env, int pname, IntBuffer params) {
		throw new UnsupportedOperationException();
	}

	public void glGetTexEnvxv (int env, int pname, int[] params, int offset) {
		throw new UnsupportedOperationException();
	}

	public void glGetTexEnvxv (int env, int pname, IntBuffer params) {
		throw new UnsupportedOperationException();
	}

	public void glGetTexParameterfv (int target, int pname, float[] params, int offset) {
		throw new UnsupportedOperationException();
	}

	public void glGetTexParameterfv (int target, int pname, FloatBuffer params) {
		throw new UnsupportedOperationException();
	}

	public void glGetTexParameteriv (int target, int pname, int[] params, int offset) {
		throw new UnsupportedOperationException();
	}

	public void glGetTexParameteriv (int target, int pname, IntBuffer params) {
		throw new UnsupportedOperationException();
	}

	public void glGetTexParameterxv (int target, int pname, int[] params, int offset) {
		throw new UnsupportedOperationException();
	}

	public void glGetTexParameterxv (int target, int pname, IntBuffer params) {
		throw new UnsupportedOperationException();
	}

	public boolean glIsBuffer (int buffer) {
		throw new UnsupportedOperationException();
	}

	public boolean glIsEnabled (int cap) {
		throw new UnsupportedOperationException();
	}

	public boolean glIsTexture (int texture) {
		throw new UnsupportedOperationException();
	}

	public void glPointParameterf (int pname, float param) {
		throw new UnsupportedOperationException();
	}

	public void glPointParameterfv (int pname, float[] params, int offset) {
		throw new UnsupportedOperationException();
	}

	public void glPointParameterfv (int pname, FloatBuffer params) {
		throw new UnsupportedOperationException();
	}

	public void glPointParameterx (int pname, int param) {
		throw new UnsupportedOperationException();
	}

	public void glPointParameterxv (int pname, int[] params, int offset) {
		throw new UnsupportedOperationException();
	}

	public void glPointParameterxv (int pname, IntBuffer params) {
		throw new UnsupportedOperationException();
	}

	public void glPointSizePointerOES (int type, int stride, Buffer pointer) {
		throw new UnsupportedOperationException();
	}

	public void glTexEnvi (int target, int pname, int param) {
		throw new UnsupportedOperationException();
	}

	public void glTexEnviv (int target, int pname, int[] params, int offset) {
		throw new UnsupportedOperationException();
	}

	public void glTexEnviv (int target, int pname, IntBuffer params) {
		throw new UnsupportedOperationException();
	}

	public void glTexParameterfv (int target, int pname, float[] params, int offset) {
		throw new UnsupportedOperationException();
	}

	public void glTexParameterfv (int target, int pname, FloatBuffer params) {
		throw new UnsupportedOperationException();
	}

	public void glTexParameteri (int target, int pname, int param) {
		throw new UnsupportedOperationException();
	}

	public void glTexParameterxv (int target, int pname, int[] params, int offset) {
		throw new UnsupportedOperationException();
	}

	public void glTexParameterxv (int target, int pname, IntBuffer params) {
		throw new UnsupportedOperationException();
	}

	private class PointerInfo {
		/** The number of coordinates per vertex. 1..4 */
		public int mSize;
		/** The type of each coordinate. */
		public int mType;
		/** The byte offset between consecutive vertices. 0 means mSize * sizeof(mType) */
		public int mStride;
		public Buffer mPointer;
		public ByteBuffer mTempByteBuffer; // Only valid during glDrawXXX calls

		public PointerInfo (int size, int type, int stride, Buffer pointer) {
			mSize = size;
			mType = type;
			mStride = stride;
			mPointer = pointer;
		}

		public int sizeof (int type) {
			switch (type) {
			case GL_UNSIGNED_BYTE:
				return 1;
			case GL_BYTE:
				return 1;
			case GL_SHORT:
				return 2;
			case GL_FIXED:
				return 4;
			case GL_FLOAT:
				return 4;
			default:
				return 0;
			}
		}

		public int getStride () {
			return mStride > 0 ? mStride : sizeof(mType) * mSize;
		}

		public void bindByteBuffer () {
			mTempByteBuffer = toByteBuffer(-1, mPointer);
		}

		public void unbindByteBuffer () {
			mTempByteBuffer = null;
		}
	}

	private Writer mLog;
	private boolean mLogArgumentNames;
	private int mArgCount;

	private PointerInfo mColorPointer;
	private PointerInfo mNormalPointer;
	private PointerInfo mTexCoordPointer;
	private PointerInfo mVertexPointer;

	boolean mColorArrayEnabled;
	boolean mNormalArrayEnabled;
	boolean mTextureCoordArrayEnabled;
	boolean mVertexArrayEnabled;

	StringBuilder mStringBuilder;
}
